#ifndef UI_LOADER_H
#define UI_LOADER_H

#include <gtkmm.h>
#include <array>
#include <functional>
#include <filesystem>
#include "Coord3D.hpp"

class UILoader
{
  public:
    UILoader();
    virtual ~UILoader();
    //block Api
    void app_show(Glib::RefPtr<Gtk::Application> & app);
    std::function<void(int,int)> funcInitPose3D;
    std::function<void()> funcDisplayPose3D;
    std::function<bool()> funcPauseControl;
    std::function<void(std::string)> funcSetRecordChange;
    std::function<void(int,int)> funcResizePose3D;
    std::function<bool()> funcPlayStatusControl;
    std::function<void(long,std::string)> funcOutput;
    //先设置任务，然后自动获取记录
    //学号，创建时间(任务ID)
    std::function<std::vector<std::tuple<long,std::string,std::string>>(long)> funcGetRecordList;
    //设置任务列表
    void SetTaskList(const std::vector<std::tuple<long,std::string,std::string>>& list);
    void DisplayCamera(char* data,int width,int height,int index);
    void DisplaySMPL(char* data,int width,int height);
    void DisplayCoord(const std::array<Cood3D,25> & data);
    void RefreshUI();
    void DisplayList(const std::deque<std::string> & list);
    void SwitchButtonToStop();
  private:
    class ModelColumns : public Glib::Object
    {
      public:
        std::string m_col_jointname;
        double m_col_x,m_col_y,m_col_z,m_col_jointoffset,m_col_rotatex,m_col_rotatey,m_col_rotatez,m_col_rotatejoint;
        static Glib::RefPtr<ModelColumns> create(const Glib::ustring & col_name)
        {
          return Glib::make_refptr_for_instance<ModelColumns>(new ModelColumns(col_name));
        }
        static Glib::RefPtr<ModelColumns> create(const Cood3D& val)
        {
          return Glib::make_refptr_for_instance<ModelColumns>(new ModelColumns(val));
        }
      protected:
        ModelColumns(const Glib::ustring & col_name)
        {}
        ModelColumns(const Cood3D& val)
          : m_col_x(val.x)
          , m_col_y(val.y)
          , m_col_z(val.z)
          , m_col_jointoffset(val.jointOffset)
          , m_col_rotatex(val.rotate_x)
          , m_col_rotatey(val.rotate_y)
          , m_col_rotatez(val.rotate_z)
          , m_col_rotatejoint(val.rotate_joint)
        {
          switch(val.jointIndex)
          {
            case 0:  m_col_jointname="Nose"; break;
            case 1:  m_col_jointname="Neck"; break;
            case 2:  m_col_jointname="RShoulder"; break;
            case 3:  m_col_jointname="RElbow"; break;
            case 4:  m_col_jointname="RWrist"; break;
            case 5:  m_col_jointname="LShoulder"; break;
            case 6:  m_col_jointname="LElbow"; break;
            case 7:  m_col_jointname="LWrist"; break;
            case 8:  m_col_jointname="MidHip"; break;
            case 9:  m_col_jointname="RHip"; break;
            case 10: m_col_jointname="RKnee"; break;
            case 11: m_col_jointname="RAnkle"; break;
            case 12: m_col_jointname="LHip"; break;
            case 13: m_col_jointname="LKnee"; break;
            case 14: m_col_jointname="LAnkle"; break;
            case 15: m_col_jointname="REye"; break;
            case 16: m_col_jointname="LEye"; break;
            case 17: m_col_jointname="REar"; break;
            case 18: m_col_jointname="LEar"; break;
            case 19: m_col_jointname="LBigToe"; break;
            case 20: m_col_jointname="LSmallToe"; break;
            case 21: m_col_jointname="LHeel"; break;
            case 22: m_col_jointname="RBigToe"; break;
            case 23: m_col_jointname="RSmallToe"; break;
            case 24: m_col_jointname="RHeel"; break;
          }
        }
    };
    void on_setup_label(const Glib::RefPtr<Gtk::ListItem>& list_item);
    Glib::RefPtr<Gio::ListStore<ModelColumns>> m_listStore;
    Glib::RefPtr<Gio::ListStore<ModelColumns>> m_listPoseInfo;
    Glib::RefPtr<Gtk::NoSelection> m_listPoseInfo_select;

    class TaskModelColumns : public Gtk::TreeModel::ColumnRecord
    {
      public:
        Gtk::TreeModelColumn<Glib::ustring> m_col_name;
        Gtk::TreeModelColumn<Glib::ustring> m_col_time;
        Gtk::TreeModelColumn<long> level;
        Gtk::TreeModelColumn<long> ID; //level=0 taskid , level=1 stuid
        Gtk::TreeModelColumn<std::string> path; //only level=1
        TaskModelColumns()
        {add(m_col_name);add(m_col_name);add(level);add(ID);add(path);}
    };
    TaskModelColumns taskColumns;
    Glib::RefPtr<Gtk::TreeStore> m_refTaskTreeModel;
    void on_listTask_row_activated(const Gtk::TreeModel::Path& path,Gtk::TreeViewColumn* column);
    void on_listTask_row_expend(const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path);

    struct CameraImageDraw
    {
      Gtk::DrawingArea* drawing=nullptr;
      std::mutex* mut=nullptr;
      Glib::RefPtr<Gdk::Pixbuf> image;
    };
    Gtk::Window* mainWindow;
    Gtk::Button* btnPauseControl;
    Gtk::Button* btnFilter;
    Gtk::Button* btnPlayControl;
    Gtk::Button* btnOutput;
    Gtk::TreeView* listTask;
    
    std::array<CameraImageDraw,5> cameraDraw;
    Gtk::GLArea* gl3DPose;
    CameraImageDraw drawSMPL;
    Gtk::ColumnView* colPoseInfo;
    template<class T> T* GetInstance(const char* name);
    Glib::RefPtr<Gtk::Builder> refBuilder;
    Glib::RefPtr<Gtk::CssProvider> cssProvider;
    bool on_gl3dpose_render(const Glib::RefPtr<Gdk::GLContext> &);
    void on_gl3dpose_resize(int width, int height);
    bool gl3dPoseFirstRender=true;
    Glib::Dispatcher patchRefreshAllUI;
    void on_refreshALLUI();
    void on_btnPlayControl_click();
    void on_btnPauseControl_click();
    void on_btnOutput_click();
    void on_CameraDraw(const Cairo::RefPtr<Cairo::Context>& cr,int width,int height,int index);
    void on_SMPLDraw(const Cairo::RefPtr<Cairo::Context>& cr,int width,int height);
};

#endif
